#include "FileOpener.h"
#include "DialogEventHandler.h"
#include <wchar.h>
#include <Commctrl.h>
#include <new>
#include <iostream>
#include <sstream>
using std::endl;

//using namespace std;

namespace SubPlayer
{
    FileOpener::FileOpener(map<wstring, wstring> fileTypeFilters):
    openTypesCount(fileTypeFilters.size())
    {
        openTypes = new COMDLG_FILTERSPEC[openTypesCount];   
        int i;
        map<wstring, wstring>::iterator it;
        for (it = fileTypeFilters.begin(), i = 0; it != fileTypeFilters.end(); it++, i++) {
            wchar_t *bufName = new wchar_t[it->first.size() + 1];
            wcscpy_s(bufName, it->first.size() + 1, it->first.c_str());
            openTypes[i].pszName = bufName;
            wchar_t *bufSpec = new wchar_t[it->second.size() + 1];
            wcscpy_s(bufSpec, it->second.size() + 1, it->second.c_str());
            openTypes[i].pszSpec = bufSpec;
        }
    }

    FileOpener::~FileOpener()
    {
        for (int i = 0; i < openTypesCount; i++) {
            delete[] openTypes[i].pszName;
            delete[] openTypes[i].pszSpec;
        }
        delete[] openTypes;
    }

    HRESULT FileOpener::ShowDialog(wstring &filePath)
    {
        // CoCreate the File Open Dialog object.
        filePath = L"";
        IFileDialog *pfd = NULL;
        //CoCreateInstance tries to create new instance of File Open Dialog. If it succeds, SUCCEDED(result) = true
        //Dont know what second and third parameter means.
        CoInitialize(NULL);
        HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
        //check if creation of File Open Dialog Instance is succesfull
        if (SUCCEEDED(hr))
        {
            //If File Open Dialog *pfd is succesfully created
            // Create an event handling object, and hook it up to the dialog.
            IFileDialogEvents *pfde = NULL;
            hr = DialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
            if (SUCCEEDED(hr))
            {
                // Hook up the event handler.
                DWORD dwCookie;
                hr = pfd->Advise(pfde, &dwCookie);
                if (SUCCEEDED(hr))
                {
                    // Set the options on the dialog.
                    DWORD dwFlags;

                    // Before setting, always get the options first in order 
                    // not to override existing options.
                    hr = pfd->GetOptions(&dwFlags);
                    if (SUCCEEDED(hr))
                    {
                        // In this case, get shell items only for file system items.
                        hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN);
                        if (SUCCEEDED(hr))
                        {
                            // Set the file types to display only. 
                            // Notice that this is a 1-based array.
                            hr = pfd->SetFileTypes(openTypesCount, openTypes);
                            if (SUCCEEDED(hr))
                            {
                                // Set the selected file type index to dllLibrary for this example.
                                hr = pfd->SetFileTypeIndex(INDEX_FIRST);
                                if (SUCCEEDED(hr))
                                {
                                    // Set the default extension to be ".dll" file.
                                    hr = pfd->SetDefaultExtension(openTypes[0].pszName);
                                    if (SUCCEEDED(hr))
                                    {
                                        // Show the dialog
                                        hr = pfd->Show(NULL);
                                        if (SUCCEEDED(hr))
                                        {
                                            // Obtain the result once the user clicks 
                                            // the 'Open' button.
                                            // The result is an IShellItem object.
                                            IShellItem *psiResult;
                                            hr = pfd->GetResult(&psiResult);
                                            if (SUCCEEDED(hr))
                                            {
                                                // We are just going to print out the 
                                                // name of the file for sample sake.
                                                PWSTR pszFilePath = NULL;
                                                hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
                                                if (SUCCEEDED(hr))
                                                {
                                                    std::wstringstream ss;
                                                    ss<<pszFilePath;
                                                    OutputDebugStringW(pszFilePath);
                                                    filePath = pszFilePath;
                                                    OutputDebugStringW(filePath.c_str());
                                                    CoTaskMemFree(pszFilePath);
                                                }
                                                psiResult->Release();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // Unhook the event handler.
                    pfd->Unadvise(dwCookie);
                }
                pfde->Release();
            }
            pfd->Release();
        }
        CoUninitialize();
        return hr;
    }

    // Instance creation helper

    HRESULT FileOpener::DialogEventHandler_CreateInstance(REFIID riid, void **ppv)
    {
        *ppv = NULL;
        DialogEventHandler *pDialogEventHandler = new (std::nothrow) DialogEventHandler();
        HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
        if (SUCCEEDED(hr))
        {
            hr = pDialogEventHandler->QueryInterface(riid, ppv);
            pDialogEventHandler->Release();
        }
        return hr;
    }

    void CreatePattern(vector<wstring> &typesList)
    {
        for (vector<wstring>::iterator it = typesList.begin(); it!= typesList.end(); it++) {
            CreatePattern(*it);
        }
    }

    void CreatePattern(wstring *&typesArray, int arraySize)
    {
        for (int i = 0; i < arraySize; i++) {
            CreatePattern(typesArray[i]);
        }
    }

    wstring GetExtension(const wstring &path)
    {
        wchar_t * extension = PathFindExtension(path.c_str());
        wstring extensionString = ++extension;
        return extensionString;
    }
}